﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using CNative.Utilities;

namespace CNative.DbUtils
{
    /// <summary>
    /// 提供关于Expression的助手方法。
    /// </summary>
    public static class ExpressionHelper
    {
        #region var
        /// <summary>表示True的SQL标记</summary>
        /// <remarks>极少一部分的DBMS以0/1表示</remarks>
        public static string TrueLiteral { get { return "1=1"; } }

        /// <summary>表示False的SQL标记<</summary>
        /// <remarks>极少一部分的DBMS以0/1表示。</remarks>
        public static string FalseLiteral { get { return "1=2"; } }

        #endregion
        #region T CastTo<T>(this Expression exp)
        /// <summary>
        /// 展开Expression的Boxing，转换为指定类型后返回。
        /// </summary>
        public static T CastTo<T>(this Expression exp)
            where T : Expression
        {
            while (exp is UnaryExpression && exp.NodeType == ExpressionType.Convert)
            {
                exp = (exp as UnaryExpression).Operand;
            }
            return (exp as T);
        }
        #endregion
        #region EvaluateValue 返回表达式树所表示的具体值
        #region ExpressionTypeCast
        /// <summary>
        /// 介绍表达式树节点的节点类型 转换为 sql关键字
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        static string ExpressionTypeCast(ExpressionType type)
        {
            switch (type)
            {
                case ExpressionType.And:
                //return " & ";
                case ExpressionType.AndAlso:
                    return " AND ";
                case ExpressionType.Equal:
                    return " =";
                case ExpressionType.GreaterThan:
                    return " >";
                case ExpressionType.GreaterThanOrEqual:
                    return ">=";
                case ExpressionType.LessThan:
                    return "<";
                case ExpressionType.LessThanOrEqual:
                    return "<=";
                case ExpressionType.NotEqual:
                    return "<>";
                case ExpressionType.Or:
                //return " | ";
                case ExpressionType.OrElse:
                    return " OR ";
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                    return "+";
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                    return "-";
                case ExpressionType.Divide:
                    return "/";
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    return "*";
                case ExpressionType.Modulo:
                    return "%";
                default:
                    return null;
            }
        }
        #endregion
        /// <summary>
        /// 返回表达式树所表示的具体值。
        /// </summary>
        /// <param name="exp">指定值的公式树</param>
        /// <returns>值</returns>
        public static object EvaluateValue(this Expression exp)
        {
            // 展开Boxing
            var expression = exp.CastTo<Expression>();

            if (expression is ConstantExpression)
            {   // 常数：返回值
                return (expression as ConstantExpression).Value;
            }
            if (expression is NewExpression)
            {   // 实例生成：返回生成的实例
                var expr = (expression as NewExpression);
                var parameters = expr.Arguments.Select(EvaluateValue).ToArray();
                return expr.Constructor.Invoke(parameters);
            }
            if (expression is NewArrayExpression)
            {   // 数组生成：返回生成的数组
                var expr = (expression as NewArrayExpression);
                return expr.Expressions.Select(EvaluateValue).ToArray();
            }
            if (expression is MethodCallExpression)
            {   // 方法调用：返回调用结果
                var expr = (expression as MethodCallExpression);
                var parameters = expr.Arguments.Select(EvaluateValue).ToArray();
                //if (parameters?.Length > 0)
                //{
                //    for (var i = 0; i < parameters.Length; i++)
                //    {
                //        if (parameters[i] is System.Reflection.MemberInfo mb)
                //            parameters[i] = mb.Name;
                //        //else
                //        //    parameters[i] = parameters[i].ToSqlValue();
                //    }
                //}
                var obj = (expr.Object == null) ? null : EvaluateValue(expr.Object);
                return expr.Method.Invoke(obj, parameters);
            }
            //if (expression is BinaryExpression)
            //{   // 方法调用：返回调用结果
            //    if (expression.NodeType == ExpressionType.Equal || expression.NodeType == ExpressionType.NotEqual
            //        || expression.NodeType == ExpressionType.GreaterThan || expression.NodeType == ExpressionType.GreaterThanOrEqual
            //        || expression.NodeType == ExpressionType.LessThan || expression.NodeType == ExpressionType.LessThanOrEqual)
            //    {
            //        var expr = (expression as BinaryExpression);
            //        var left = EvaluateValue(expr.Left);
            //        var op = ExpressionTypeCast(expression.NodeType);
            //        var obj = EvaluateValue(expr.Right);
            //        return $"{left}{op}{obj}";
            //    }
            //}
            if (expression is InvocationExpression)
            {   // 拉姆达等调用：返回调用结果
                var invocation = (expression as InvocationExpression);
                var parameters = invocation.Arguments.Select(x => Expression.Parameter(x.Type)).ToArray();
                var arguments = invocation.Arguments.Select(EvaluateValue).ToArray();
                var lambda = Expression.Lambda(invocation, parameters);
                return lambda.Compile().DynamicInvoke(arguments);
            }
            if (expression is BinaryExpression && expression.NodeType == ExpressionType.ArrayIndex)
            {   //数组等索引：返回该索引的值
                var expr = (expression as BinaryExpression);
                var array = (Array)EvaluateValue(expr.Left);
                var index = expr.Right.Type == typeof(int)
                          ? (int)EvaluateValue(expr.Right)
                          : (long)EvaluateValue(expr.Right);
                return array.GetValue(index);
            }

            //成员（字段或属性）：取出属性/字段值
            //※如果是实例成员，则递归把握实例值
            var member = (expression as MemberExpression);
            if (member != null)
            {
                if (member.Member.MemberType == MemberTypes.Property)
                {
                    var info = (PropertyInfo)member.Member;
                    return (member.Expression != null)
                        ? member.Expression.NodeType == ExpressionType.Parameter ? member.Member//.Name
                            : info.FastGetValue(EvaluateValue(member.Expression))
                        : info.FastGetStaticValue();
                }
                else if (member.Member.MemberType == MemberTypes.Field)
                {
                    var info = (FieldInfo)member.Member;
                    return (member.Expression != null)
                        ? member.Expression.NodeType == ExpressionType.Parameter ? member.Member//.Name
                            : info.FastGetValue(EvaluateValue(member.Expression))
                        : info.FastGetStaticValue();
                }
            }

            // 在上述处理中无法确定值：执行并取出值
            return Expression.Lambda(expression).Compile().DynamicInvoke();
        }
        #endregion
        #region GetMemberNames
        /// <summary>
        /// 返回参数表达式指定的成员名称指定成员的集合。
        /// </summary>
        /// <param name="expression">成员名的表达式</param>
        /// <returns>成员名称集合</returns>
        public static IEnumerable<string> GetMemberNames(Expression expression, BaseProvider dbProvider = null, string tableAlias = "")
        {
            if (expression == null) return new string[0];

            var suffixLeft = dbProvider?.SuffixLeft;
            var suffixRigh = dbProvider?.SuffixRigh;
            tableAlias = tableAlias.IsNullOrEmpty() ? "" : tableAlias.Replace(".", "") + ".";
            var fieldMeta = tableAlias + suffixLeft + "{0}" + suffixRigh;

            var valueSql = TryBindFieldExpr(dbProvider, null, expression, null, tableAlias);
            if (valueSql.IsNotNullOrEmpty())
            {   // 否则取出更新值绑定
                var colname = "";
                if (expression is MethodCallExpression mc && mc.Arguments?.Count > 0)
                {
                    var field = ExpressionHelper.EvaluateValue(mc.Arguments[0]);
                    if (field is System.Reflection.MemberInfo mb)
                        colname = Funs.FormatFieldName(tableAlias, mb.GetColumnName(), dbProvider);
                }
                return new[] { valueSql +" "+ colname };
            }
            if (expression is NewExpression ne)
            {
                var members = ne.Members;
                if (members.Count > 0)
                {
                    return members.Select(m => string.Format(fieldMeta, m.GetColumnName()));
                }
            }
            else if (expression is MemberInitExpression mie)
            {
                var members = mie.Bindings;
                if (members.Count > 0)
                {
                    return members.Select(m => string.Format(fieldMeta, m.Member.GetColumnName()));
                }
            }
            else if (expression is MemberExpression me)
            {
                return new[] { string.Format(fieldMeta, me.Member.GetColumnName()) };
            }
            else if (expression is UnaryExpression ue)
            {
                var member = (ue.Operand as MemberExpression);
                if (member != null)
                    return new[] { string.Format(fieldMeta, member.Member.GetColumnName()) };
            }
            throw new ArgumentException("argument must be Expression specifiing an item name", expression.ToString());
        }
        #endregion
        //----------------------------------------------------------------------------------------------------------------------------------
        #region BuildWhere
        ///// <summary>
        ///// 根据参数指定的条件式生成Where条件SQLwhere也进行条件值的参数绑定。
        ///// </summary>
        ///// <param name="parameters">数据参数对象</param>
        ///// <param name="where">条件式</param>
        ///// <typeparam name="TClass">映射到表格的类型</typeparam>
        ///// <returns>生成的Where句（没有条件指定时为空字符）</returns>
        ///// <remarks>如果在parameters中指定了null，则不进行参数绑定，生成静态SQL。</remarks>
        //public static string BuildWhere<TClass>(SqlEntity sqlent, Expression<Func<TClass, bool>> where, bool? isAnd = null, bool useTableAlias = true, string tableAlias = "") where TClass : class, new()
        //{
        //    if (where == null)
        //    {
        //        return string.Empty;
        //    }
        //    var tableInfo = Funs.GetDbTableInfo<TClass>(sqlent.DbHelper);
        //    tableAlias = tableAlias.Replace(".", "");
        //    if (useTableAlias)
        //        tableAlias = tableAlias.IsNullOrEmpty() ? SqlAliasHelper.GetTableAlias<TClass>() : tableAlias;
        //    return $"{(isAnd.HasValue == false ? "" : isAnd.Value ? "AND" : "OR")} ({BuildWhere(sqlent, tableInfo, where.Body, sqlent.DbHelper.SqlDbProvider.SuffixLeft, sqlent.DbHelper.SqlDbProvider.SuffixRigh, tableAlias)})";
        //}
        //// <summary>
        ///// 根据参数指定的条件式生成Where条件。
        ///// </summary>
        ///// <param name="parameters">参数对象</param>
        ///// <param name="tableInfo">表格信息</param>
        ///// <param name="expression">条件式</param>
        ///// <returns>条件式的SQL</returns>
        //internal static string BuildWhere(SqlEntity sqlent, DbTableInfo tableInfo, Expression expression, string suffixLeft, string suffixRigh, string tableAlias = "")
        //{
        //    var fieldMeta = tableAlias + suffixLeft + "{0}" + suffixRigh;
        //    #region 本地取列函数
        //    // 本地函数相当：如果Expression是Where条件的列，则返回该列信息
        //    Func<Expression, DbColumnInfo> getIfOperandIsConditionColumn = (exp) => GetIfOperandIsConditionColumn(exp, sqlent?.DbHelper);
        //    #endregion

        //    #region 指定二元运算符以外的特殊表达式的处理
        //    var binaryExpr = ExpressionHelper.CastTo<BinaryExpression>(expression);
        //    if (binaryExpr == null)
        //    {   // 指定二元运算符以外的特殊表达式的处理

        //        // 「!」判断是否指定了NOT/bool型的属性
        //        var unaryExpr = ExpressionHelper.CastTo<UnaryExpression>(expression);
        //        var isNot = (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Not);
        //        var column = getIfOperandIsConditionColumn(isNot ? unaryExpr.Operand : expression);
        //        if (column != null && column.PropertyInfo.PropertyType == typeof(bool))
        //        {   // 作为bool列值的条件组装
        //            return column.Name + "=" + (isNot ? FalseLiteral : TrueLiteral);
        //        }
        //        if (isNot)
        //        {   //作为NOT条件组装
        //            return "not(" + BuildWhere(sqlent, tableInfo, unaryExpr.Operand, suffixLeft, suffixRigh, tableAlias) + ")";
        //        }

        //        // 用固有的SQL条件式记述用方法记述式木的情况下，调用SQL条件式生成方法来组装SQL
        //        var sqlExprBindResult = TryBindWhereExpr(sqlent, null, expression, tableInfo, tableAlias);
        //        if (sqlExprBindResult != null)
        //        {
        //            return sqlExprBindResult;
        //        }

        //        // 如果记述了成为bool值的变量和处理，则组装该值
        //        var boolValue = ExpressionHelper.EvaluateValue(expression);
        //        if (boolValue is bool)
        //        {
        //            return ((bool)boolValue == true) ? TrueLiteral : FalseLiteral;
        //        }

        //        // 非任何一个例外
        //        throw new InvalidExpressionException(expression.ToString());
        //    }
        //    #endregion

        //    #region And/Or条件的解释
        //    // And/Or条件的解释
        //    switch (binaryExpr.NodeType)
        //    {
        //        case ExpressionType.AndAlso:
        //            var andLeft = BuildWhere(sqlent, tableInfo, binaryExpr.Left, suffixLeft, suffixRigh, tableAlias);
        //            if (andLeft == FalseLiteral)
        //            {   // 「left && right」中的left中确定了假的情况下，不进行右侧的展开
        //                return andLeft;
        //            }
        //            var andRight = BuildWhere(sqlent, tableInfo, binaryExpr.Right, suffixLeft, suffixRigh, tableAlias);
        //            // 如果真的确定在左边右边的某一个，则只以另一个为条件，否则组装and条件式
        //            return (andLeft == TrueLiteral) ? andRight
        //                : (andRight == TrueLiteral) ? andLeft
        //                                            : andLeft + " AND " + andRight;
        //        case ExpressionType.OrElse:
        //            var orLeft = BuildWhere(sqlent, tableInfo, binaryExpr.Left, suffixLeft, suffixRigh, tableAlias);
        //            if (orLeft == TrueLiteral)
        //            {   // 「left || right」中的left中确定了真，则不展开右边缘
        //                return orLeft;
        //            }
        //            var orRight = BuildWhere(sqlent, tableInfo, binaryExpr.Right, suffixLeft, suffixRigh, tableAlias);
        //            // 如果在左边右边确定了假，则只以另一个为条件，否则组装或条件式
        //            return (orLeft == FalseLiteral) ? orRight
        //                : (orRight == FalseLiteral) ? orLeft
        //                                            : "(" + orLeft + " OR " + orRight + ")";
        //    }
        //    #endregion

        //    #region 两边都没有列指定
        //    var leftMember = getIfOperandIsConditionColumn(binaryExpr.Left);
        //    var rightMember = getIfOperandIsConditionColumn(binaryExpr.Right);
        //    if (leftMember == null && rightMember == null)
        //    {
        //        #region 函数处理
        //        if (expression.NodeType == ExpressionType.Equal || expression.NodeType == ExpressionType.NotEqual
        //            || expression.NodeType == ExpressionType.GreaterThan || expression.NodeType == ExpressionType.GreaterThanOrEqual
        //            || expression.NodeType == ExpressionType.LessThan || expression.NodeType == ExpressionType.LessThanOrEqual)
        //        {
        //            var expr = (expression as BinaryExpression);
        //            object left , right;
        //            if (binaryExpr.Left is MethodCallExpression)
        //            {
        //                left = TryBindWhereExpr(sqlent, null, binaryExpr.Left, tableInfo, tableAlias);                        
        //            }
        //            else { left = EvaluateValue(expr.Left).ToSqlValue(); }
        //            var opss = ExpressionTypeCast(expression.NodeType);
        //            if (binaryExpr.Right is MethodCallExpression)
        //            {
        //                right = TryBindWhereExpr(sqlent, null, binaryExpr.Right, tableInfo, tableAlias);
        //            }
        //            else { right = EvaluateValue(expr.Right).ToSqlValue(); }
        //            return $"{left}{opss}{right}";
        //        }
        //        #endregion

        //        // 两边都没有列指定：扩展到具体的bool值
        //        var boolValue = ExpressionHelper.EvaluateValue(binaryExpr);
        //        if (!(boolValue is bool))
        //        {
        //            throw new InvalidExpressionException(binaryExpr.ToString());
        //        }
        //        return ((bool)boolValue ? TrueLiteral : FalseLiteral);
        //    }
        //    #endregion

        //    #region 解释比较运算符
        //    // 解释比较运算符
        //    string op;
        //    var opEnd = string.Empty;
        //    var opIsNot = false;
        //    switch (binaryExpr.NodeType)
        //    {
        //        case ExpressionType.Equal:
        //            op = "="; break;
        //        case ExpressionType.NotEqual:
        //            op = "<>"; opIsNot = true; break;
        //        case ExpressionType.GreaterThan:
        //            op = ">"; break;
        //        case ExpressionType.GreaterThanOrEqual:
        //            op = ">="; break;
        //        case ExpressionType.LessThan:
        //            op = "<"; break;
        //        case ExpressionType.LessThanOrEqual:
        //            op = "<="; break;
        //        default:
        //            throw new InvalidExpressionException(expression.ToString());
        //    }

        //    if (leftMember != null && rightMember != null)
        //    {   // 两边都是指定列名的情况下不需要取得参数值，根据两边的列名组装条件式
        //        return leftMember.Name + op + rightMember.Name;
        //    }
        //    #endregion

        //    #region 组装SQL条件式
        //    var condColumn = leftMember ?? rightMember;
        //    var valueExpression = ExpressionHelper.CastTo<Expression>(condColumn == leftMember ? binaryExpr.Right : binaryExpr.Left);
        //    // 用固有的SQL条件式记述用方法指定值的情况下，调用SQL条件式生成方法来组装SQL
        //    {
        //        var sqlExprBindResult = TryBindWhereExpr(sqlent, condColumn, valueExpression, tableInfo, tableAlias);
        //        if (sqlExprBindResult != null)
        //        {
        //            return sqlExprBindResult;
        //        }
        //    }

        //    //把握列指定侧的指定值，组装SQL条件式
        //    var value = ExpressionHelper.EvaluateValue(valueExpression);
        //    if (value == null)
        //    {
        //        var mname = string.Format(fieldMeta, condColumn.Name);// 
        //        return mname + " is" + (opIsNot ? " not" : "") + " null";
        //    }
        //    else
        //    {
        //        if (sqlent.AddDbParameter(condColumn.Name, value,  out string parameterName, "bwp_", tableInfo))
        //        {
        //            var bindedValueSql = parameterName;
        //            var mname = string.Format(fieldMeta, condColumn.Name);// tableAlias + suffixLeft + condColumn.Name + suffixRigh;
        //            return (condColumn == leftMember
        //                ? mname + op + bindedValueSql
        //                : bindedValueSql + op + mname);
        //        }
        //        else return "";
        //    }
        //    #endregion

        //}
        #endregion
        #region BuildWhere
        /// <summary>
        /// 根据参数指定的条件式生成Where条件SQLwhere也进行条件值的参数绑定。
        /// </summary>
        /// <param name="parameters">数据参数对象</param>
        /// <param name="where">条件式</param>
        /// <typeparam name="TClass">映射到表格的类型</typeparam>
        /// <returns>生成的Where句（没有条件指定时为空字符）</returns>
        /// <remarks>如果在parameters中指定了null，则不进行参数绑定，生成静态SQL。</remarks>
        public static string BuildWhere<TClass>(SqlEntity sqlent, Expression<Func<TClass, bool>> where, bool? isAnd = null, string tableAlias = "") where TClass : class, new()
        {
            if (where == null)
            {
                return string.Empty;
            }
            tableAlias = tableAlias.NullToStr().Replace(".", "");
            if (tableAlias.IsNotNullOrEmpty())
                SqlAliasHelper.GetTableAlias<TClass>(tableAlias);
            return BuildWhere(sqlent, where, isAnd);
        }
        /// <summary>
        /// 根据参数指定的条件式生成Where条件SQLwhere也进行条件值的参数绑定。
        /// </summary>
        /// <param name="parameters">数据参数对象</param>
        /// <param name="where">条件式</param>
        /// <typeparam name="TClass">映射到表格的类型</typeparam>
        /// <returns>生成的Where句（没有条件指定时为空字符）</returns>
        /// <remarks>如果在parameters中指定了null，则不进行参数绑定，生成静态SQL。</remarks>
        public static string BuildWhere<TClass>(SqlEntity sqlent, Expression<Func<TClass, bool>> where, bool? isAnd = null) where TClass : class, new()
        {
            if (where == null)
            {
                return string.Empty;
            }
            return $"{(isAnd.HasValue == false ? "" : isAnd.Value ? "AND" : "OR")} ({BuildWhere(sqlent, where.Body)})";
        }
        /// <summary>
        /// 根据参数指定的条件式生成Where条件SQLwhere也进行条件值的参数绑定。
        /// </summary>
        /// <param name="parameters">数据参数对象</param>
        /// <param name="where">条件式</param>
        /// <typeparam name="TClass">映射到表格的类型</typeparam>
        /// <returns>生成的Where句（没有条件指定时为空字符）</returns>
        /// <remarks>如果在parameters中指定了null，则不进行参数绑定，生成静态SQL。</remarks>
        public static string BuildWhere<TClass>(SqlEntity sqlent, Expression where, bool? isAnd = null) where TClass : class, new()
        {
            if (where == null)
            {
                return string.Empty;
            }
            return $"{(isAnd.HasValue == false ? "" : isAnd.Value ? "AND" : "OR")} ({BuildWhere(sqlent, where)})";
        }
        // <summary>
        /// 根据参数指定的条件式生成Where条件。
        /// </summary>
        /// <param name="parameters">参数对象</param>
        /// <param name="tableInfo">表格信息</param>
        /// <param name="expression">条件式</param>
        /// <returns>条件式的SQL</returns>
        public static string BuildWhere(SqlEntity sqlent, Expression expression)
        {
            //var fieldMeta = "{0}" + sqlent?.DbHelper?.SqlDbProvider.SuffixLeft + "{1}" + sqlent?.DbHelper?.SqlDbProvider.SuffixRigh;
            #region 本地取列函数
            // 本地函数相当：如果Expression是Where条件的列，则返回该列信息
            Func<Expression, DbColumnInfo> getIfOperandIsConditionColumn = (exp) => GetIfOperandIsConditionColumn(exp, sqlent?.DbHelper);
            #endregion

            #region 指定二元运算符以外的特殊表达式的处理
            var binaryExpr = ExpressionHelper.CastTo<BinaryExpression>(expression);
            if (binaryExpr == null)
            {   // 指定二元运算符以外的特殊表达式的处理

                // 「!」判断是否指定了NOT/bool型的属性
                var unaryExpr = ExpressionHelper.CastTo<UnaryExpression>(expression);
                var isNot = (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Not);
                var column = getIfOperandIsConditionColumn(isNot ? unaryExpr.Operand : expression);
                if (column != null && column.PropertyInfo.PropertyType == typeof(bool))
                {   // 作为bool列值的条件组装
                    return Funs.FormatFieldName(column, sqlent)
                        + "=" + (isNot ? FalseLiteral : TrueLiteral);
                }
                if (isNot)
                {   //作为NOT条件组装
                    return "not(" + BuildWhere(sqlent, unaryExpr.Operand) + ")";
                }

                // 用固有的SQL条件式记述用方法记述式木的情况下，调用SQL条件式生成方法来组装SQL
                var sqlExprBindResult = TryBindWhereExpr(sqlent, null, expression);
                if (sqlExprBindResult != null)
                {
                    return sqlExprBindResult;
                }

                // 如果记述了成为bool值的变量和处理，则组装该值
                var boolValue = ExpressionHelper.EvaluateValue(expression);
                if (boolValue is bool)
                {
                    return ((bool)boolValue == true) ? TrueLiteral : FalseLiteral;
                }

                // 非任何一个例外
                throw new InvalidExpressionException(expression.ToString());
            }
            #endregion

            #region And/Or条件的解释
            // And/Or条件的解释
            switch (binaryExpr.NodeType)
            {
                case ExpressionType.AndAlso:
                    var andLeft = BuildWhere(sqlent, binaryExpr.Left);
                    if (andLeft == FalseLiteral)
                    {   // 「left && right」中的left中确定了假的情况下，不进行右侧的展开
                        return andLeft;
                    }
                    var andRight = BuildWhere(sqlent, binaryExpr.Right);
                    // 如果真的确定在左边右边的某一个，则只以另一个为条件，否则组装and条件式
                    return (andLeft == TrueLiteral) ? andRight
                        : (andRight == TrueLiteral) ? andLeft
                                                    : andLeft + " AND " + andRight;
                case ExpressionType.OrElse:
                    var orLeft = BuildWhere(sqlent, binaryExpr.Left);
                    if (orLeft == TrueLiteral)
                    {   // 「left || right」中的left中确定了真，则不展开右边缘
                        return orLeft;
                    }
                    var orRight = BuildWhere(sqlent, binaryExpr.Right);
                    // 如果在左边右边确定了假，则只以另一个为条件，否则组装或条件式
                    return (orLeft == FalseLiteral) ? orRight
                        : (orRight == FalseLiteral) ? orLeft
                                                    : "(" + orLeft + " OR " + orRight + ")";
            }
            #endregion

            #region 两边都没有列指定
            var leftMember = getIfOperandIsConditionColumn(binaryExpr.Left);
            var rightMember = getIfOperandIsConditionColumn(binaryExpr.Right);
            if (leftMember == null && rightMember == null)
            {
                #region 函数处理
                if (expression.NodeType == ExpressionType.Equal || expression.NodeType == ExpressionType.NotEqual
                    || expression.NodeType == ExpressionType.GreaterThan || expression.NodeType == ExpressionType.GreaterThanOrEqual
                    || expression.NodeType == ExpressionType.LessThan || expression.NodeType == ExpressionType.LessThanOrEqual)
                {
                    var expr = (expression as BinaryExpression);
                    object left, right;
                    if (binaryExpr.Left is MethodCallExpression)
                    {
                        left = TryBindWhereExpr(sqlent, null, binaryExpr.Left);
                    }
                    else { left = EvaluateValue(expr.Left).ToSqlValue(); }
                    var opss = ExpressionTypeCast(expression.NodeType);
                    if (binaryExpr.Right is MethodCallExpression)
                    {
                        right = TryBindWhereExpr(sqlent, null, binaryExpr.Right);
                    }
                    else { right = EvaluateValue(expr.Right).ToSqlValue(); }
                    return $"{left}{opss}{right}";
                }
                #endregion

                // 两边都没有列指定：扩展到具体的bool值
                var boolValue = ExpressionHelper.EvaluateValue(binaryExpr);
                if (!(boolValue is bool))
                {
                    throw new InvalidExpressionException(binaryExpr.ToString());
                }
                return ((bool)boolValue ? TrueLiteral : FalseLiteral);
            }
            #endregion

            #region 解释比较运算符
            // 解释比较运算符
            string op;
            var opEnd = string.Empty;
            var opIsNot = false;
            switch (binaryExpr.NodeType)
            {
                case ExpressionType.Equal:
                    op = "="; break;
                case ExpressionType.NotEqual:
                    op = "<>"; opIsNot = true; break;
                case ExpressionType.GreaterThan:
                    op = ">"; break;
                case ExpressionType.GreaterThanOrEqual:
                    op = ">="; break;
                case ExpressionType.LessThan:
                    op = "<"; break;
                case ExpressionType.LessThanOrEqual:
                    op = "<="; break;
                default:
                    throw new InvalidExpressionException(expression.ToString());
            }

            if (leftMember != null && rightMember != null)
            {   // 两边都是指定列名的情况下不需要取得参数值，根据两边的列名组装条件式
                return Funs.FormatFieldName(leftMember, sqlent)
                    + op
                    + Funs.FormatFieldName(rightMember, sqlent);
            }
            #endregion

            #region 组装SQL条件式
            var condColumn = leftMember ?? rightMember;
            var valueExpression = ExpressionHelper.CastTo<Expression>(condColumn == leftMember ? binaryExpr.Right : binaryExpr.Left);
            // 用固有的SQL条件式记述用方法指定值的情况下，调用SQL条件式生成方法来组装SQL
            {
                var sqlExprBindResult = TryBindWhereExpr(sqlent, condColumn, valueExpression);
                if (sqlExprBindResult != null)
                {
                    return sqlExprBindResult;
                }
            }

            //把握列指定侧的指定值，组装SQL条件式
            var value = ExpressionHelper.EvaluateValue(valueExpression);

            if (value == null)
            {
                return Funs.FormatFieldName(condColumn, sqlent)
                    + " is" + (opIsNot ? " not" : "") + " null";
            }
            else
            {
                var tableInfo = Funs.GetDbTableInfo(sqlent.DbHelper, condColumn.PropertyInfo?.DeclaringType);
                if (sqlent.AddDbParameter(condColumn.Name, value, out string parameterName, "bwp_", tableInfo))
                {
                    var bindedValueSql = parameterName;
                    var mname = Funs.FormatFieldName(condColumn, sqlent);
                    return (condColumn == leftMember
                        ? mname + op + bindedValueSql
                        : bindedValueSql + op + mname);
                }
                else return "";
            }
            #endregion

        }
        #endregion
        #region TryBindWhereExpr
        static DbColumnInfo GetIfOperandIsConditionColumn(Expression exp, IDbHelper dbHelper)
        {
            var me = ExpressionHelper.CastTo<MemberExpression>(exp);
            if (me == null || me.Expression == null || me.Expression.NodeType != ExpressionType.Parameter)
            {   // 如果不是关于参数的成员，则不视为Where条件列
                return null;
            }
            var prop = me.Member as PropertyInfo;
            if (prop == null)
            {   // 如果不是属性项目，则不视为Where条件列
                return null;
            }
            var tableInfo = Funs.GetDbTableInfo(dbHelper, prop.DeclaringType);
            // 如果对应于tableInfo的列，则返回该列信息
            return tableInfo?.TableInfo?.FirstOrDefault(c => c.PropertyInfo == prop);
        }
        /// <summary>
        ///绑定值用固有的SQL条件式记述用方法指定值时，调用/SQL条件式生成方法进行参数绑定・SQL组装参数对象
        /// </summary>
        /// <param name="parameters">参数对象</param>
        /// <param name="column">绑定对象的列</param>
        /// <param name="expression">表示绑定值的式树</param>
        /// <param name="opIsNot">条件式在not中生成时，true</param>
        /// <returns>生成的SQL表示字符串。但是，如果绑定值不是DapperAid固有的SQL条件式记述用方法，则null</returns>
        internal static string TryBindWhereExpr(SqlEntity sqlent, DbColumnInfo column, Expression expression, DbTableInfo tableInfo, string tableAlias = "")
        {
            var methodCallExpression = ExpressionHelper.CastTo<MethodCallExpression>(expression);
            if (methodCallExpression != null && methodCallExpression.Method != null
                && (methodCallExpression.Method.DeclaringType == typeof(WhereExpr)
                 || methodCallExpression.Method.DeclaringType == typeof(FieldExpr)))
            {
                if (column == null)
                {
                    //var colname = ExpressionHelper.EvaluateValue(methodCallExpression.Arguments[0]);
                    column = GetIfOperandIsConditionColumn(methodCallExpression.Arguments[0], sqlent?.DbHelper);
                }
                return WhereExpr.BuildSql(
                    methodCallExpression.Method.Name,
                    methodCallExpression.Arguments,
                    sqlent,
                    column,
                    tableInfo,
                  tableAlias);
            }
            return null;
        }
        internal static string TryBindWhereExpr(SqlEntity sqlent, DbColumnInfo column, Expression expression)
        {
            var methodCallExpression = ExpressionHelper.CastTo<MethodCallExpression>(expression);
            if (methodCallExpression != null && methodCallExpression.Method != null
                && (methodCallExpression.Method.DeclaringType == typeof(WhereExpr)
                 || methodCallExpression.Method.DeclaringType == typeof(FieldExpr)))
            {
                DbTableInfo tableInfo = null;
                var tableAlias = "";
                if (column == null)
                {
                    column = GetIfOperandIsConditionColumn(methodCallExpression.Arguments[0], sqlent?.DbHelper);
                }
                if (column != null && column.PropertyInfo != null)
                {
                    tableInfo = Funs.GetDbTableInfo(sqlent.DbHelper, column.PropertyInfo.DeclaringType);
                    tableAlias = SqlAliasHelper.GetTableAlias(column.PropertyInfo?.DeclaringType);
                }
                return WhereExpr.BuildSql(
                    methodCallExpression.Method.Name,
                    methodCallExpression.Arguments,
                    sqlent,
                    column,
                    tableInfo,
                  tableAlias);
            }
            return null;
        }
        #endregion
        #region TryBindFieldExpr
        /// <summary>
        ///绑定值用固有的SQL组装参数对象
        /// </summary>
        /// <param name="parameters">参数对象</param>
        /// <param name="column">绑定对象的列</param>
        /// <param name="expression">表示绑定值的式树</param>
        /// <param name="opIsNot">条件式在not中生成时，true</param>
        /// <returns>生成的SQL表示字符串。但是，如果绑定值不是DapperAid固有的SQL条件式记述用方法，则null</returns>
        internal static string TryBindFieldExpr(BaseProvider dbProvider, DbColumnInfo column, Expression expression, DbTableInfo tableInfo, string tableAlias = "")
        {
            var methodCallExpression = ExpressionHelper.CastTo<MethodCallExpression>(expression);
            if (methodCallExpression != null && methodCallExpression.Method != null
                && methodCallExpression.Method.DeclaringType == typeof(FieldExpr))
            {
                //if (column == null)
                //{
                //    //var colname = ExpressionHelper.EvaluateValue(methodCallExpression.Arguments[0]);
                //    column = GetIfOperandIsConditionColumn(methodCallExpression.Arguments[0], tableInfo);
                //}
                return FieldExpr.BuildSql(dbProvider,
                    methodCallExpression.Method.Name,
                    methodCallExpression.Arguments,
                  //column,
                  // tableInfo,
                  tableAlias);
            }
            return null;
        }
        #endregion
        #region AddDbParameter
        /// <summary>
        /// 添加参数
        /// </summary>
        /// <param name="propName">参数名称</param>
        /// <param name="val">参数值</param>
        /// <param name="sqlent"></param>
        /// <param name="sqlstr"></param>
        /// <param name="strand"></param>
        /// <param name="oper"></param>
        /// <param name="paramSuffix">参数前缀</param>
        internal static bool AddDbParameter(string propName, object val, SqlEntity sqlent, out string parameterName, string paramSuffix = "wp_", DbTableInfo tb = null)
        {
            parameterName = "";
            if (sqlent == null) return false;
            return sqlent.AddDbParameter(propName, val, out parameterName, paramSuffix, tb);
        }
        #endregion
    }
}
